package com.ljx.itbbs.server.article.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.ljx.itbbs.common.constant.CacheConstants;
import com.ljx.itbbs.common.exception.BusinessException;
import com.ljx.itbbs.common.manager.AsyncManager;
import com.ljx.itbbs.server.article.domain.dto.SignKeyDto;
import com.ljx.itbbs.server.article.domain.enums.IncreaseExpEnum;
import com.ljx.itbbs.server.article.domain.enums.IncreaseIntegralEnum;
import com.ljx.itbbs.server.article.domain.enums.SignEnum;
import com.ljx.itbbs.server.article.domain.vo.resp.SignInfoResp;
import com.ljx.itbbs.server.article.service.SignService;
import com.ljx.itbbs.server.article.service.handler.ArticleAsyncHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2024-03-27  09:48
 */
@Service
public class SignServiceImpl implements SignService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void signIn(Long userId) {
        SignKeyDto signKeyDto = getSignKey(userId);
        // 获取今天是这个月的第几天
        int dayOfMonth = signKeyDto.getNow().getDayOfMonth();
        if (Boolean.TRUE.equals(stringRedisTemplate.opsForValue().getBit(signKeyDto.getKey(), dayOfMonth - 1))){
            throw new BusinessException("请勿重复签到");
        }
        // 签到
        stringRedisTemplate.opsForValue().setBit(signKeyDto.getKey(), dayOfMonth - 1, true);
        // 签到成功加经验和积分
        AsyncManager.me().execute(ArticleAsyncHandler.increaseUserIntegralAndExp(
                userId, IncreaseExpEnum.SIGN.getExp(), IncreaseIntegralEnum.SIGN.getIntegral()
        ));
    }

    private SignKeyDto getSignKey(Long userId) {
        LocalDateTime now = LocalDateTime.now();
        String format = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = CacheConstants.getKey(CacheConstants.SIGN_KEY, userId + format);
        return new SignKeyDto(key, now);
    }

    @Override
    public SignInfoResp getSignInfo(Long userId) {
        SignKeyDto signKeyDto = getSignKey(userId);
        // 获取今天是这个月的第几天
        int dayOfMonth = signKeyDto.getNow().getDayOfMonth();
        // 查询签到记录
        List<Long> result = stringRedisTemplate.opsForValue().bitField(signKeyDto.getKey(),
                BitFieldSubCommands.create() .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
        if (CollUtil.isEmpty(result)){
            return new SignInfoResp(false, 0);
        }

        return calSignContinueDays(result);
    }

    /**
     * 计算连续的天数
     * @param records
     * @return
     */
    private SignInfoResp calSignContinueDays(List<Long> records) {
        Long record = records.get(0);
        String binaryString = Long.toBinaryString(record);
        int res = 0, len = binaryString.length() - 1, index = len;
        while(index >= 0){
            if(binaryString.charAt(index) == SignEnum.SIGN.getType()){
                res ++;
            } else {
                break;
            }
            index --;
        }
        return new SignInfoResp(binaryString.charAt(len) == SignEnum.SIGN.getType(), res);
    }
}
